package com.eastfair.imaster.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.eastfair.boot.service.SuperCacheServiceImpl;
import com.eastfair.cache.company.ProductCacheKeyBuilder;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.code.ExceptionCode;
import com.eastfair.core.model.CacheKeyBuilder;
import com.eastfair.core.utils.ValidateUtil;
import com.eastfair.enums.AuditStateEnum;
import com.eastfair.imaster.dao.ProductMapper;
import com.eastfair.imaster.dto.ProductPageQuery;
import com.eastfair.imaster.entity.ExhibitorProduct;
import com.eastfair.imaster.entity.Product;
import com.eastfair.imaster.service.ExhibitorProductService;
import com.eastfair.imaster.service.ProductService;
import com.eastfair.projectcore.api.ProjectCoreServiceFeign;
import com.eastfair.core.snowflake.DefaultUidGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 业务实现类
 * 产品表
 * </p>
 *
 * @author liuxiaobai
 * @date 2021-08-19
 */
@Slf4j
@Service
@DS("#thread.tenant")
public class ProductServiceImpl extends SuperCacheServiceImpl<ProductMapper, Product> implements ProductService {

    @Autowired
    ProjectCoreServiceFeign projectCoreServiceFeign;
    @Autowired
    ExhibitorProductService exhibitorProductService;

    @Override
    protected CacheKeyBuilder cacheKeyBuilder() {
        return new ProductCacheKeyBuilder();
    }

    /**************sharding 分库分表操作 *****************/
    @Override
    public boolean updateByIdOfShard(Product entity) {
        UpdateWrapper<Product> updateWrapper = new UpdateWrapper<>();
        //可将指定字段更新为null
        updateWrapper.lambda().eq(Product::getProjectId, entity.getProjectId()).eq(Product::getId, entity.getId());
        entity.setProjectId(null);
        //删除缓存
        delCache(entity);
        return SqlHelper.retBool(this.getBaseMapper().update(entity, updateWrapper));
    }

    @Override
    protected R<Boolean> handlerSave(Product model) {
        //雪花ID
        model.setId(DefaultUidGenerator.getUidOfProjectId(ContextUtil.getProjectId()));
        return R.successDef();
    }


    @Override
    public R<List<String>> updateBatchPublish(List<Long> ids, Long exhibitionId) {
        //获取产品列表
        List<Product> products = queryByIds(ids);
        if (products.isEmpty()) {
            return R.fail(ExceptionCode.NOT_FOUND);
        }
        List<String> failNames = new ArrayList<>();
        products.forEach(product -> {
            //发布时校验必填项 校验不通过不做发布操作
            //todo 校验修改
            if (!ValidateUtil.validateSimple(product)) {
                failNames.add(product.getName());
                return;
            }
            //批量修改产品绑定的当前展会ID
            product.setExhibitionId(exhibitionId);
            //需求：无论是什么状态下的产品，每次编辑完产品，点击发布都需要主办审核
            product.setVerifyState(AuditStateEnum.PENDING.getCode());
            //取消草稿状态
            product.setIsDraft(BusinessConstant.ENABLE_NO);
        });
        //批量update产品
        this.updateBatchById(products);
        return R.success(failNames);
    }

    @Override
    public R<Boolean> updateBatchAudit(List<Long> ids, AuditStateEnum auditState, String verifyContent) {
        //获取产品列表
        List<Product> products = queryByIds(ids);
        if (products.isEmpty()) {
            return R.fail(ExceptionCode.NOT_FOUND);
        }
        UpdateWrapper<Product> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda()
                .set(Product::getVerifyState, auditState.getCode())
                .set(Product::getVerifyContent, verifyContent)
                .eq(Product::getProjectId, ContextUtil.getProjectId())
                .in(Product::getId, ids);
        super.update(updateWrapper);
        //不是审核通过直接返回 不需要后续操作
        if (!AuditStateEnum.APPROVE.eq(auditState)) {
            return R.success();
        }

        //审核通过 复制为展品
        List<ExhibitorProduct> exhibitorProducts = new ArrayList<>(products.size());
        products.forEach(product -> {
            ExhibitorProduct exhibitorProduct = new ExhibitorProduct();
            //复制bean 忽略id
            BeanUtil.copyProperties(product, exhibitorProduct, "id");
            exhibitorProducts.add(exhibitorProduct);
        });
        //产品upsert到对应展品
        this.exhibitorProductService.upsert(exhibitorProducts);
        //todo 还需同步问卷

        //保证事物一致

        return R.success();
    }

    @Override
    public R<Boolean> updateBatch(ProductPageQuery query) {
        List<Long> ids = query.getIds();
        Long projectId = ContextUtil.getProjectId();
        Long exhibitionId = ContextUtil.getExhibitionId();
        List<ExhibitorProduct> exhibitorProducts = new ArrayList<>(ids.size());
        ids.forEach(id -> {
            Product product = Product.builder()
                    .id(id)
                    .projectId(projectId)
                    .scope(query.getScope())
                    .isEnable(query.getIsEnable())
                    .build();
            updateByIdOfShard(product);
            exhibitorProducts.add(ExhibitorProduct.builder()
                    .projectId(projectId)
                    .productId(id)
                    .exhibitionId(exhibitionId)
                    .scope(query.getScope())
                    .isEnabled(query.getIsEnable())
                    .build());
        });
        this.exhibitorProductService.upsert(exhibitorProducts);
        return R.success();
    }

    @Override
    public List<Product> queryByIds(List<Long> ids) {
        QueryWrapper<Product> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(Product::getProjectId, ContextUtil.getProjectId())
                .in(Product::getId, ids);
        return list(queryWrapper);
    }

}
